// Contient toutes les spécifications de classes nécessaires
// pour représenter l'arbre abstrait
#ifndef ARBRE_H_
#define ARBRE_H_

#include <vector>
#include <iostream>
#include <iomanip>
using namespace std;

#include "Symbole.h"
#include "NoeudVisitor.h"
#include "Valeur.h"
#include "MotsCles.h"

////////////////////////////////////////////////////////////////////////////////
class Noeud
{
// classe abstraite dont dériveront toutes les classes servant à représenter l'arbre abstrait
// Remarque : la classe ne contient aucun constructeur
public:
    virtual Valeur*  getValeur()
    {
        Valeur* valeur = new ValeurInt ( 0 );
        return valeur;
    } ; // méthode pure (non implémentée) qui rend la classe abstraite

    virtual ~Noeud() {} // présence d'un destructeur virtuel conseillée dans les classes abstraites
    virtual void Accept ( NoeudVisitor& ) {}

};


////////////////////////////////////////////////////////////////////////////////
class NoeudSeqDecl : public Noeud
{
// classe pour représenter un noeud "sequence de declaration"
// qui a autant de fils que de declaration dans la séquence
public:
    NoeudSeqDecl();   // construit une séquence de declaration vide
    ~NoeudSeqDecl() {} // à cause du destructeur virtuel de la classe Noeud
    int getSize(); // accesseur
    Valeur* getValeur(); // évalue chaque instruction de la séquence
    void ajouteDecl ( Noeud* declaration );  // ajoute une declaration à la séquence
    void Accept ( NoeudVisitor& visitor ); // Pattern visitor

private:
    vector<Noeud *> tabDecl; // pour stocker les declarations de la séquence
};


////////////////////////////////////////////////////////////////////////////////
class NoeudDeclaration : public Noeud
{
// classe pour représenter un noeud "affectation"
// composé de 2 fils : la variable et l'expression qu'on lui affecte
public:
    NoeudDeclaration ( Noeud* variable, string type ); // construit une affectation
    ~NoeudDeclaration() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue l'expression et affecte sa valeur à la variable
    Symbole getType()
    {
        return type;
    }; // évalue l'expression et affecte sa valeur à la variable
//     void afficher(unsigned short indentation=0); // affiche l'affectation
    void Accept ( NoeudVisitor& visitor );

private:
    string type;
    Noeud* variable;
};


////////////////////////////////////////////////////////////////////////////////
class NoeudSeqInst : public Noeud
{
// classe pour représenter un noeud "sequence d'instruction"
// qui a autant de fils que d'instructions dans la séquence
public:
    NoeudSeqInst();   // construit une séquence d'instruction vide
    ~NoeudSeqInst() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue chaque instruction de la séquence
    int getSize(); //accesseur
    void ajouteInstruction ( Noeud* instruction );  // ajoute une instruction à la séquence
    void Accept ( NoeudVisitor& visitor ); // Pattern visitor

private:
    vector<Noeud *> tabInst; // pour stocker les instructions de la séquence
};


////////////////////////////////////////////////////////////////////////////////
class NoeudProg : public Noeud
{
// classe pour représenter un noeud "programme"
// qui a sequence de declaration et un autre de d'instruction
public:
    NoeudProg(Noeud* seqDecl, Noeud* seqInst);   // construit un programmme compose de sd et de si
    ~NoeudProg() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue les deux partie sd puis si
    void Accept ( NoeudVisitor& visitor ); // Pattern visitor
    Noeud* getDecl() { return seqDecl; } //accesseur
    Noeud* getinst() { return seqInst; }  //accesseur
    
private:
    Noeud* seqInst; // pour stocker la si
    Noeud* seqDecl; // pour stocker la sd
};



////////////////////////////////////////////////////////////////////////////////
class NoeudSi : public Noeud
{
// classe pour représenter un noeud "si"
// composé de 3 fils : la seqInst et la condition d'entre, et le si suivant s'il existe.
public:
    NoeudSi ( Noeud* expbool, Noeud* seqInst, Noeud* siSuivant ); // construit un si
    ~NoeudSi() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue l'expression et affecte sa valeur à la variable
    void Accept ( NoeudVisitor& visitor );
    Noeud* getExpBool() { return expBool; } //accesseur

private:
    Noeud* seqInst;
    Noeud* expBool;
    Noeud* siSuivant;
};


////////////////////////////////////////////////////////////////////////////////
class NoeudPour : public Noeud
{
// classe pour représenter un noeud "pour"
// composé de 24 fils : la premiere affectation, la condition de sortie , la deuxieme affectation et la seqInst
public:
    NoeudPour ( Noeud* aff, Noeud* affDroite, Noeud* expbool, Noeud* seqInst ); // construit un pour
    ~NoeudPour() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue l'expression et affecte sa valeur à la variable
    void Accept ( NoeudVisitor& visitor ); // pattern visitor
    Noeud* getExpBool() { return expBool; } //accesseur
    Noeud* getAffG() { return aff; } //accesseur
    Noeud* getAffD() { return affDroite; } //accesseur
    
private:
    Noeud* seqInst;
    Noeud* expBool;
    Noeud* aff;
    Noeud* affDroite;
};


////////////////////////////////////////////////////////////////////////////////
class NoeudTantQue : public Noeud
{
// classe pour représenter un noeud "tant que"
// composé de 2 fils : la seqInst et la condition de sortie
public:
    NoeudTantQue ( Noeud* expbool, Noeud* seqInst ); // construit un tantque
    ~NoeudTantQue() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue l'expression et affecte sa valeur à la variable
    void Accept ( NoeudVisitor& visitor );  // pattern visitor

private:
    Noeud* seqInst;
    Noeud* expBool;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudRepeter : public Noeud
{
// classe pour représenter un noeud "repeter"
// composé de 2 fils : la seqInst et la condition de sortie
public:
    NoeudRepeter ( Noeud* expbool, Noeud* seqInst ); // construit une affectation
    ~NoeudRepeter() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue l'expression et affecte sa valeur à la variable
    void Accept ( NoeudVisitor& visitor ); // pattern visitor

private:
    Noeud* seqInst;
    Noeud* expBool;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudAffectation : public Noeud
{
// classe pour représenter un noeud "affectation"
// composé de 2 fils : la variable et l'expression qu'on lui affecte
public:
    NoeudAffectation ( Noeud* variable, Noeud* expression ); // construit une affectation
    ~NoeudAffectation() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue l'expression et affecte sa valeur à la variable
      void Accept ( NoeudVisitor& visitor); // pattern visitor
      
    Noeud* getVariable() { return variable; } //accesseur
    Noeud* getExpression() { return expression; } //accesseur

protected:
    Noeud* variable;
    Noeud* expression;
};

class NoeudAffectationPour : public NoeudAffectation
// Le noeud affectation pour se disting du "normal" dans le fait qu'il n'a pas de ; apres lui, mais sa forme est la meme
{
  public:
      NoeudAffectationPour ( Noeud* variable, Noeud* expression ); // construit une affectation
    ~NoeudAffectationPour() {} // à cause du destructeur virtuel de la classe Noeud
      void Accept ( NoeudVisitor& visitor);
};


////////////////////////////////////////////////////////////////////////////////
class NoeudLire : public Noeud
{
// classe pour représenter un noeud "lire"
// composé de 1 fils : la varialbe que l'on veut affecter
public:
    NoeudLire ( Noeud* variable ); // construit une expression
    ~NoeudLire() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // revoie la valeur de l'expression
    void Accept ( NoeudVisitor& visitor );

private:
    Noeud* variable;
};


////////////////////////////////////////////////////////////////////////////////
class NoeudEcrire : public Noeud
{
// classe pour représenter un noeud "ecrire"
// composé de 1 fils : l'expression qu'on veux afficher
public:
    NoeudEcrire ( Noeud* expression ); // construit une expression
    ~NoeudEcrire() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // revoie la valeur de l'expression
    void Accept ( NoeudVisitor& visitor );

private:
    Noeud* expression;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudOperateurBinaire : public Noeud
{
// classe pour représenter un noeud "opération arithmétique" composé d'un opérateur (+-*/)
// et de 2 fils : l'opérande gauche et l'opérande droit
public:
    NoeudOperateurBinaire ( Symbole operateur, Noeud* operandeGauche, Noeud* operandeDroit );
    // construit une opération binaire : operandeGauche operateur OperandeDroit
    ~NoeudOperateurBinaire() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue l'operande gauche, l'operande droit et applique l'opérateur
    void Accept ( NoeudVisitor& visitor );
    Symbole getOperateur()
    {
        return operateur;
    }
    Noeud* getOperandeGauche()
    {
        return operandeGauche;
    }
    Noeud* getOperandeDroit()
    {
        return operandeDroit;
    }
    void ErreurDiv (Noeud* op); // si on divise par 0 affiche une message d'erreur et, leve une exeption

private:
    Symbole operateur;
    Noeud*  operandeGauche;
    Noeud*  operandeDroit;
};

#endif /* ARBRE_H_ */
